;********************************************************
; exception_isr_64.asm
;
; contains CPU exception ISRs
; all exception ISRs execute within their own stack.
; this should be stack IST_2 for all but the #DF
; (double fault) exception, which executes on IST_3
;********************************************************
; entry point for main exception controller
; param1 (rdi) = ptr to register state table

extern CPUExceptionHandler

;********************************************************
; global definitions for each handler


global CPU_EXCEPTION_0_DE
global CPU_EXCEPTION_1_DB
global CPU_EXCEPTION_2_NMI
global CPU_EXCEPTION_3_BP
global CPU_EXCEPTION_4_OF
global CPU_EXCEPTION_5_BR
global CPU_EXCEPTION_6_UD
global CPU_EXCEPTION_7_NM
global CPU_EXCEPTION_8_DF
global CPU_EXCEPTION_10_TS
global CPU_EXCEPTION_11_NP
global CPU_EXCEPTION_12_SS
global CPU_EXCEPTION_13_GP
global CPU_EXCEPTION_14_PF
global CPU_EXCEPTION_16_MF
global CPU_EXCEPTION_17_AC
global CPU_EXCEPTION_18_MC
global CPU_EXCEPTION_19_XF
global CPU_EXCEPTION_30_SX


;********************************************************
; internal function to save the processor state to the
; stack according to the order layed out in
; CPU_exception.h
; and restore the state after calling the main handler
; before returning

section .text

SaveRegisterState:
	; save each of the registers to the space pointed to by rsp
	; in reverse order
	; (lowest address points to where rax is saved)
	; param1 (rsp) = ptr to where to store the register state (base)
	; save gp registers
	push 	rax
	push 	rbx
	push 	rcx
	push 	rdx
	push 	rsi
	push 	rdi
	push 	r8
	push 	r9
	push 	r10
	push 	r11
	push 	r12
	push 	r13
	push 	r14
	push 	r15

	; save control registers
	mov 	rax, cr0
	push 	rax
	mov 	rax, 0
	push 	rax
	mov 	rax, cr2
	push 	rax
	mov 	rax, cr3
	push 	rax
	mov 	rax, cr4
	push 	rax

	; save FPU state
	sub		rsp, 3072			; make rsp point to where to save the FPU state
	fxsave	[rsp]

	; set the parameter for the C call
	; pass pointer to base of state table
	mov 	rdi, rsp

	; call C handler
	mov 	rax, CPUExceptionHandler
	call 	rax

	; C handler returned
	; rax points to area on stack (should be same as rdi when this was called)
	mov 	rsp, rax	; set stack pointer to returned value

	; check given CR3 is different and load it if necessary
	mov 	rax, [rsp + 3080]	; get CR3 value from stack
	mov 	rbx, cr3			; get current CR3
	cmp 	rbx, rax			; check if they are equal
	je		.cr3_done
	mov		cr3, rax			; load cr3 as they weren't equal

.cr3_done:
	; cr3 is loaded
	; restore FPU state
	fxrstor	[rsp]

	; skip to gp registers
	add 	rsp, 40 + 3072

	; restore gp registers
	pop 	r15
	pop 	r14
	pop 	r13
	pop 	r12
	pop 	r11
	pop 	r10
	pop 	r9
	pop 	r8
	pop 	rdi
	pop 	rsi
	pop 	rdx
	pop 	rcx
	pop 	rbx
	pop 	rax

	; point rsp to bottom of RSI stack frame
	add 	rsp, 16

	; finished, return
	iretq




;********************************************************
; the ISRs
;********************************************************
; Divide-By-Zero-Error
; #DE
; vector 0

CPU_EXCEPTION_0_DE:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 0

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Debug
; #DB
; vector 1

CPU_EXCEPTION_1_DB:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 1

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Non Maskable Interrupt
; #NMI
; vector 2

CPU_EXCEPTION_2_NMI:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 2

	; go to register save
	jmp 	SaveRegisterState





;********************************************************
; Break Point
; #BP
; vector 3

CPU_EXCEPTION_3_BP:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 3

	; go to register save
	jmp 	SaveRegisterState




;********************************************************
; Overflow
; #OF
; vector 4

CPU_EXCEPTION_4_OF:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 4

	; go to register save
	jmp 	SaveRegisterState



;********************************************************
; Bound Range
; #BR
; vector 5

CPU_EXCEPTION_5_BR:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 5

	; go to register save
	jmp 	SaveRegisterState



;********************************************************
; Invalid Opcode
; #UD
; vector 6

CPU_EXCEPTION_6_UD:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 6

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Device-Not-Available
; #NM
; vector 7

CPU_EXCEPTION_7_NM:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 7

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Double Fault
; #DF
; vector 8

CPU_EXCEPTION_8_DF:
	; exception entry point
	; disable interrupts
	cli

	; push exception vector
	push 	QWORD 8

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Invalid TSS
; #TS
; vector 10

CPU_EXCEPTION_10_TS:
	; exception entry point
	; disable interrupts
	cli

	; push exception vector
	push 	QWORD 10

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Segment Not Present
; #NP
; vector 11

CPU_EXCEPTION_11_NP:
	; exception entry point
	; disable interrupts
	cli

	; push exception vector
	push 	QWORD 11

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Stack
; #SS
; vector 12

CPU_EXCEPTION_12_SS:
	; exception entry point
	; disable interrupts
	cli

	; push exception vector
	push 	QWORD 12

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; General Protection
; #GP
; vector 13

CPU_EXCEPTION_13_GP:
	; exception entry point
	; disable interrupts
	cli

	; push exception vector
	push 	QWORD 13

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Page Fault
; #PF
; vector 14

CPU_EXCEPTION_14_PF:
	; exception entry point
	; disable interrupts
	cli

	; push exception vector
	push 	QWORD 14

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; x87-Floating-Point Pending Exception
; #MF
; vector 16

CPU_EXCEPTION_16_MF:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 16

	; go to register save
	jmp 	SaveRegisterState



;********************************************************
; Alignment-check
; #AC
; vector 17

CPU_EXCEPTION_17_AC:
	; exception entry point
	; disable interrupts
	cli

	; push exception vector
	push 	QWORD 17

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Machine-Check
; #MC
; vector 18

CPU_EXCEPTION_18_MC:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 18

	; go to register save
	jmp 	SaveRegisterState



;********************************************************
; SIMD floating-point exception
; #XF
; vector 19

CPU_EXCEPTION_19_XF:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 19

	; go to register save
	jmp 	SaveRegisterState


;********************************************************
; Security Exception
; #SX
; vector 30

CPU_EXCEPTION_30_SX:
	; exception entry point
	; disable interrupts
	cli

	; push dummy error code
	push 	QWORD 0

	; push exception vector
	push 	QWORD 30

	; go to register save
	jmp 	SaveRegisterState


























